package e.odbo.spring;

import com.openbravo.data.basic.BasicException;
import com.openbravo.data.loader.DBSession;
import com.openbravo.data.loader.dialect.Derby.DerbyDBDialect;
import com.openbravo.data.loader.dialect.H2.H2DBDialect;
import com.openbravo.data.loader.dialect.HSQLDB.HSQLDBDialect;
import com.openbravo.data.loader.dialect.MySQL.MySQLDBDialect;
import com.openbravo.data.loader.dialect.Oracle.OracleDBDialect;
import com.openbravo.data.loader.dialect.PostgreSQL.PostgreSQLDBDialect;
import com.openbravo.data.loader.dialect.SQLite.SQLiteDBDialect;
import com.openbravo.data.loader.dialect.SessionDBGeneric;
import com.openbravo.data.loader.dialect.SessionDialect;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

public class SpringDataSourceSession extends DBSession {


    private PlatformTransactionManager txManager;

    private TransactionStatus status=null;

    private String dialectName;

    private int isolationLevel;

    public SpringDataSourceSession(DataSource dataSource,String dialectName) throws BasicException {
       this(dataSource,dialectName,null);
    }

    public SpringDataSourceSession(DataSource dataSource,String dialectName,int isolationLevel) throws BasicException {
        this(dataSource,dialectName,null,isolationLevel);
    }

    public SpringDataSourceSession(DataSource dataSource,String dialectName,PlatformTransactionManager txManager) throws BasicException {
        this(dataSource,dialectName,null,TransactionDefinition.PROPAGATION_REQUIRES_NEW);
    }

    public SpringDataSourceSession(DataSource dataSource,String dialectName,PlatformTransactionManager txManager,int isolationLevel) throws BasicException {
        super(dataSource);
        this.dialectName=dialectName;
        this.txManager=txManager;
        this.isolationLevel=isolationLevel;
    }

    @Override
    public void connect() throws BasicException {
    }

    @Override
    public void close() {
    }

    @Override
    public Connection getConnection() throws BasicException {
        Connection connection=null;
        try {
            connection=dataSource.getConnection();
        } catch (SQLException e) {
            throw new BasicException(e);
        }
        return connection;
    }

    @Override
    public void begin() throws BasicException {
        if(txManager==null) {
            super.begin();
            return;
        }
        if(status!=null)
            throw new BasicException("in transaction");
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(isolationLevel);// 事物隔离级别，开启新事务
        status = txManager.getTransaction(def);
    }

    @Override
    public void commit() throws BasicException {
        if(txManager==null) {
            super.commit();
            return;
        }
        if(status==null)
            throw new BasicException("not in transaction");
        txManager.commit(status);
        status=null;

    }

    @Override
    public void rollback() throws BasicException {
        if(txManager==null) {
            super.rollback();
            return;
        }
        if(status==null)
            throw new BasicException("not in transaction");
        txManager.rollback(status);
        status=null;
    }

    @Override
    public boolean isTransaction() {
        if(txManager==null) {
            return super.isTransaction();
        }
        return status!=null;
    }

    @Override
    public String getURL() throws BasicException {
        String url="no sample";
        try{
            url=getConnection().getMetaData().getURL();
        }catch (SQLException e){
            throw new BasicException(e);
        }
        return url;
    }

    @Override
    public String getPlatform() {
        return "SPRING JDBC";
    }

    @Override
    public Connection getConnection(boolean readOnly) throws BasicException {
        return getConnection();
    }

    @Override
    public SessionDialect getDialect() {
        String sdbmanager =dialectName;
        if ("HSQL".equalsIgnoreCase(sdbmanager)) {
            return new HSQLDBDialect();
        } else if ("MySQL".equalsIgnoreCase(sdbmanager)) {
            return new MySQLDBDialect();
        } else if ("PostgreSQL".equalsIgnoreCase(sdbmanager)) {
            return new PostgreSQLDBDialect();
        } else if ("Oracle".equalsIgnoreCase(sdbmanager)) {
            return new OracleDBDialect();
        } else if ("Derby".equalsIgnoreCase(sdbmanager)) {
            return new DerbyDBDialect();
        } else if ("SQLite".equalsIgnoreCase(sdbmanager)) {
            return new SQLiteDBDialect();
        }else if ("H2".equalsIgnoreCase(sdbmanager)) {
            return new H2DBDialect();
        }
        return new SessionDBGeneric("default");
    }
}
